package com.stu.widget;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.graphics.PointF;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;

import com.stu.graph.*;
import com.stu.info.GraphFragment;

public class GraphView extends View {
	
	static final public class GraphViewConfig {
		static public final int GRID_X = 10;
		static public final int GRID_Y = 6;
		static public final int LABEL_COLOR = Color.BLACK;
		static public final int GRID_COLOR = Color.DKGRAY;
		static public final int LEGEND_HEIGHT = 15;
		static public final int LEGEND_WIDTH = 120;
		static public final float SCROLL_THRESHOLD = 8;
		static public final float SCROLL_AMOUNT = 7;
	}

	private Paint gridPaint, legendKeyPaint, legendRectPaint, textPaint, dataPaint;
	private boolean showLegend, showGrid;
	private LegendAlign legendAlign;
	private RectF legendRect;
	private GraphFragment graphFragment;

	public int gridX, gridY;

	public enum LegendAlign {
		TOP, MIDDLE, BOTTOM
	}

	public GraphView( Context c ) {
		super( c );
		init();
	}

	public GraphView(Context context, AttributeSet attrs) {
		super(context, attrs);
		init();
	}
	
	public GraphView(Context context, AttributeSet attrs, int defaultStyle) {
		super(context, attrs, defaultStyle);
		init();
	}

	private void init() {
		gridX = GraphViewConfig.GRID_X;
		gridY = GraphViewConfig.GRID_Y;
		graphFragment = null;
		dataPaint = new Paint();
		dataPaint.setAntiAlias(true);

		gridPaint = new Paint();
		gridPaint.setColor( GraphViewConfig.GRID_COLOR );
		
		textPaint = new Paint();
		textPaint.setColor( GraphViewConfig.LABEL_COLOR );
		
		legendRectPaint = new Paint();
		legendRectPaint.setARGB(180, 100, 100, 100);
		legendKeyPaint = new Paint();

		legendRect = new RectF();
		showLegend = false;
		showGrid = false;
		legendAlign = LegendAlign.MIDDLE;
	}

	public void setFragment( GraphFragment f ) {
		graphFragment = f;
	}
	
	@Override
	protected void onDraw(Canvas canvas) {
		float x, y, dy, dx;
		int height = getHeight();
		int width = getWidth();
		
		if( showGrid ) {
			// horizontal grid lines
			dy = height / gridY;
			y = 0;
			for( int i = 0; i <= gridY; i++ ) {
				canvas.drawLine(0, y, width, y, gridPaint);
				y += dy;
			}
	
			// vertical grid lines
			dx = width / gridX;
			x = 0;
			for( int i = 0; i <= gridX; i++ ) {
				canvas.drawLine(x, 0, x, height, gridPaint);
				x += dx;
			}
		}

		if( graphFragment == null )
			return;
		
		if( graphFragment.graphSeries == null || graphFragment.graphSeries.isEmpty() )
			return;

		float lastEndY, lastEndX, valX, valY, startX, startY, endX, endY;
		// draw data
		if( graphFragment.maxY < gridY )
			dy = gridY - graphFragment.minY;
		else
			dy = graphFragment.maxY - graphFragment.minY;
		for( DataSeries d : graphFragment.graphSeries ) {
			if( !d.visible )
				continue;

			lastEndY = -1;
			lastEndX = -1;
			
			dataPaint.setStrokeWidth(d.style.thickness);
			dataPaint.setColor(d.style.color);
	
			for( PointF v : d.values ) {
				valY = v.y - graphFragment.minY;
				y = height * (valY / dy);
	
				if( v.x > graphFragment.maxX )
					valX = graphFragment.maxX - graphFragment.minX;		// clip the value to the window
				else
					valX = v.x - graphFragment.minX;
				x = width * (valX / (float)gridX);
	
				if( d.values.size() == 1 )
					canvas.drawPoint(x, height-y, dataPaint);
				else if( lastEndX != -1 ) {
					startX = lastEndX;
					startY = height - lastEndY;
					endX = x;
					endY = height - y;
					canvas.drawLine(startX, startY, endX, endY, dataPaint);
				}
				lastEndY = y;
				lastEndX = x;
			}
		}

		if (showLegend) {
			// rect
			float legendHeight = (GraphViewConfig.LEGEND_HEIGHT + 5) * graphFragment.graphSeries.size() + 5;
			float lLeft = width - GraphViewConfig.LEGEND_WIDTH - 10;
			float lTop = 0;
			switch (legendAlign) {
				case TOP:
					lTop = 10;
					break;
				case MIDDLE:
					lTop = height/2 - legendHeight/2;
					break;
				case BOTTOM:
					lTop = height - legendHeight - 10;
			}
			float lRight = lLeft + GraphViewConfig.LEGEND_WIDTH;
			float lBottom = lTop + legendHeight;
			legendRect.set(lLeft, lTop, lRight, lBottom);
			canvas.drawRoundRect(legendRect, 8, 8, legendRectPaint);
	
			textPaint.setTextAlign(Align.LEFT);
			int i = 0;
			for( DataSeries d : graphFragment.graphSeries ) {
				if( !d.visible )
					continue;
				legendKeyPaint.setColor( d.style.color );
				legendRect.set( lLeft + 5, lTop + 5 + (i * (GraphViewConfig.LEGEND_HEIGHT + 5)),
				  lLeft + 5 + GraphViewConfig.LEGEND_HEIGHT, lTop + ((i + 1) * (GraphViewConfig.LEGEND_HEIGHT + 5)) );
				canvas.drawRect(legendRect, legendKeyPaint);
				if( d.name != null ) {
					x = lLeft + 5 + GraphViewConfig.LEGEND_HEIGHT + 5;
					y = lTop + GraphViewConfig.LEGEND_HEIGHT + (i * (GraphViewConfig.LEGEND_HEIGHT + 5));
					canvas.drawText(d.name, x, y, textPaint);
				}
				i++;
			}
		}
	}

	public void setLegendAlign(LegendAlign legendAlign) {
		this.legendAlign = legendAlign;
		invalidate();
	}


	public void showLegend(boolean show) {
		showLegend = show;
		invalidate();
	}
	
	public void showGrid( boolean show ) {
		showGrid = show;
		invalidate();
	}
}
